/*
 * @Descripttion:
 * @LastEditors: chen.long
 * @LastEditTime: 2024-02-24 14:56:28
 */
import { EventBus } from './lib/event';
import {
  addSandboxCacheWithOptions,
  getOptionsById,
  getYbMicroById
} from './lib/sandboxCache';
import importHTML, { processCssLoader } from './modules/entry';
import YbMicro from './modules/sandbox';
import { addLoading } from './modules/shadow';
import { cacheOptions, startOptions } from './types/index.type';
import { mergeOptions, stopMainAppRun } from './utils';

export const bus = new EventBus(Date.now().toString());

/**
 * 强制中断主应用运行
 * YBMICRO.__YBMICRO 如果为true说明当前运行环境是子应用
 * window.__POWERED_BY_YBMICRO__ 如果为false说明子应用还没初始化完成
 * 上述条件同时成立说明主应用代码在iframe的loading阶段混入进来了，中断代码执行
 */
if (window.__YBMICRO && !window.__POWERED_BY_YBMICRO__) {
  stopMainAppRun();
}

/**
 * @Author: chen.long
 * @Descripttion: 缓存子应用配置
 * @Param:
 * @param {cacheOptions} options
 */
export function setupApp(options: cacheOptions): void {
  if (options.name) addSandboxCacheWithOptions(options.name, options);
}

/**
 * @Author: chen.long
 * @Descripttion: 运行子应用
 * @Param:
 */
export async function startApp(
  startOptions: startOptions
): Promise<Function | void> {
  const sandbox = getYbMicroById(startOptions.name);
  const cacheOptions = getOptionsById(startOptions.name);
  // 合并缓存配置
  const options = mergeOptions(startOptions, cacheOptions);
  const { name, url, props, el, loading, lifecycles } = options;
  // 已经初始化过的应用，快速渲染
  if (sandbox) {
    sandbox.lifecycles = lifecycles;
    // 保活
    await sandbox.active({
      url,
      el,
      props
    });
    // 但是没有执行的情况
    if (!sandbox.execFlag) {
      sandbox.lifecycles?.beforeLoad?.(sandbox.iframe.contentWindow);
      const { getExternalScripts } = await importHTML({
        url,
        opts: {
          loadError: sandbox.lifecycles.loadError
        }
      });
      await sandbox.start(getExternalScripts);
    }
    sandbox.lifecycles?.activated?.(sandbox.iframe.contentWindow);
    return sandbox.destroy;
  }

  // 设置loading
  addLoading(el, loading);
  const newSandbox = new YbMicro({
    name,
    url,
    lifecycles
  });
  newSandbox.lifecycles?.beforeLoad?.(newSandbox.iframe.contentWindow);
  const { template, getExternalScripts, getExternalStyleSheets } =
    await importHTML({
      url,
      opts: {
        loadError: newSandbox.lifecycles.loadError
      }
    });

  const processedHtml = await processCssLoader(
    newSandbox,
    template,
    getExternalStyleSheets
  );
  await newSandbox.active({
    url,
    template: processedHtml,
    el,
    props
  });
  await newSandbox.start(getExternalScripts);
  return newSandbox.destroy;
}

/**
 * @Author: chen.long
 * @Descripttion: 销毁子应用
 * @Param:
 * @param {string} id 需要销毁的子应用id
 */
export function destroyApp(id: string): void {
  const sandbox = getYbMicroById(id);
  if (sandbox) {
    sandbox.destroy();
  }
}
